
// Copyright (C) 2009 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Derm.BindGen
{
	/// <summary>
	/// Function abstraction.
	/// </summary>
	partial class Function
	{
		#region Constructors & Destructor

		/// <summary>
		/// Function constructor.
		/// </summary>
		/// <param name="sig">
		/// A <see cref="System.String"/> specifying the function signature.
		/// </param>
		public Function(string sig)
		{
			ParseSignature(sig);
		}

		/// <summary>
		/// Utility for parsing function signature.
		/// </summary>
		/// <param name="sig">
		/// A <see cref="System.String"/> specifying the function signature.
		/// </param>
		private void ParseSignature(string sig)
		{
			string[] sTokens;

			Debug.Assert(sig != null);

			// Split function signature (function name, parameters in order)
			sTokens = sig.Split(new char[] {' ', '\t', '(',')', ','}, StringSplitOptions.RemoveEmptyEntries);

			// Store name
			mName = sTokens[0];
			// Store parameters (in declaration order)
			for (int i = 1; i < sTokens.Length; i++)
				mParameters.Add(new Parameter(sTokens[i]));
		}

		/// <summary>
		/// Function name.
		/// </summary>
		private string mName = null;

		#endregion

		#region Function Parameters

		public Parameter GetParameter(string name)
		{
			Parameter pTemplate = new Parameter(name);
			
			foreach (Parameter p in mParameters)
				if (p.Name == pTemplate.Name)
					return (p);
			return (null);
		}

		public List<Parameter> GetParameters()
		{
			return (new List<Parameter>(mParameters));
		}

		/// <summary>
		/// Function parameters.
		/// </summary>
		private List<Parameter> mParameters = new List<Parameter>();

		#endregion

		#region Function Returned Value

		/// <summary>
		/// Determine whether a value is returned.
		/// </summary>
		public bool HasReturnedValue
		{
			get { return ((ReturnedValueType != "void") && (ReturnedValueType != "*") && (ReturnedValueType != "VOID")); }
		}

		/// <summary>
		/// Returned value.
		/// </summary>
		public string ReturnedValueType = "void";

		#endregion

		#region Function Import

		/// <summary>
		/// String prefixes at function import name.
		/// </summary>
		public string ImportNamePrefix = "";

		/// <summary>
		/// Function name to be used in import statements.
		/// </summary>
		public string ImportName
		{
			get { return (ImportNamePrefix+mName); }
		}

		public string[] GetImportDeclaration()
		{
			List<string> sImport = new List<string>();

			// Compose input declaration
			sImport.Add("[System.Security.SuppressUnmanagedCodeSecurity()]");
			sImport.Add("[System.Runtime.InteropServices.DllImport(Library, EntryPoint = \""+ImportName+"\", ExactSpelling = true)]");
			if (IsSafeImplementation(mParameters) == false)
				sImport.Add("internal extern static unsafe "+GetImportSignature()+";");
			else
				sImport.Add("internal extern static "+GetImportSignature()+";");

			return (sImport.ToArray());
		}

		/// <summary>
		/// Compose function import signature.
		/// </summary>
		/// <returns>
		/// It returns a string specifying the function signature used by import.
		/// </returns>
		private string GetImportSignature()
		{
			string sigFunctParams, sigRet;
			int pNo = mParameters.Count;

			#region Returned Value

			// Returned value
			sigRet = SpecParser.GetCsUnsafeType(ReturnedValueType);
			if (sigRet == "byte*") sigRet = "IntPtr";		// XXX

			#endregion

			#region Parameters

			// Function parameters
			sigFunctParams = "(";
			foreach (Parameter p in mParameters) {
				string sigParam;

				// Basic declaration
				sigParam = p.ImportTypeName + " " + p.Name;
				// Parameter attributes (marshal)
				if (p.MDirection == Parameter.MarshalDirection.Out)
					sigParam = "[Out]" + sigParam;
				// Parameter separator
				if (--pNo > 0) sigParam += ", ";

				// Append parameter declaration
				sigFunctParams += sigParam;
			}
			sigFunctParams += ")";

			#endregion

			return (sigRet + " " + ImportName + sigFunctParams);
		}

		#endregion

		#region Function Delegate

		/// <summary>
		/// Function delegate name.
		/// </summary>
		public string DelegateName
		{
			get { return ("p"+ImportName); }
		}

		/// <summary>
		/// Compose function delegate.
		/// </summary>
		/// <returns>
		/// It returns an array of strings specifying the function delegate definition.
		/// </returns>
		public string[] GetDelegateDeclaration()
		{
			List<string> sDelegate = new List<string>();
			
			string sigFunct, sigFunctParams, sigRet;
			int pNo = mParameters.Count;

			#region Returned Value

			// Returned value
			sigRet = GetDelegateReturnType();

			#endregion

			#region Parameters

			// Function parameters
			sigFunctParams = "(";
			foreach (Parameter p in mParameters) {
				// Append parameter declaration
				sigFunctParams += p.DelegateName;
				// Parameter separator
				if (--pNo > 0) sigFunctParams += ", ";
			}
			sigFunctParams += ")";

			#endregion

			// Complete function signature
			sigFunct = sigRet + " " + ImportName + sigFunctParams;

			// Compose input declaration
			sDelegate.Add("[System.Security.SuppressUnmanagedCodeSecurity()]");
			if (IsSafeImplementation(mParameters) == false)
				sDelegate.Add("internal unsafe delegate "+sigFunct+";");
			else
				sDelegate.Add("internal delegate "+sigFunct+";");

			// Thread static attribute
			if (ImportNamePrefix == "gl")
				sDelegate.Add("[ThreadStatic]");

			sDelegate.Add("internal static "+ImportName+" "+DelegateName+" = null;");

			return (sDelegate.ToArray());
		}
		
		private string GetDelegateReturnType()
		{
			// Returned value
			string sigRet = SpecParser.GetCsUnsafeType(ReturnedValueType);
			
			if (sigRet == "byte*") sigRet = "IntPtr";
			
			return (sigRet);
		}

		#endregion

		#region Function Implementation

		/// <summary>
		/// Function implementation name.
		/// </summary>
		/// <remarks>
		/// Initially this property is equals to the function name defined in the function
		/// specification. It can be set to impose a specific name in the case is possible
		/// to determine an alternative name (function name suffixes reduction).
		/// </remarks>
		public string ImplementationName
		{
			get { if (mImplementationName == null) return (mName); else return (mImplementationName); }
			set { mImplementationName = value; }
		}

		public bool IsCompatibleSubset(Function subset)
		{
			if ((subset.Alias == null) || (subset.Alias != this.ImplementationName)) {
				// Parameter count
				if (mParameters.Count != subset.mParameters.Count)
					return (false);

				// Parameter type
				for (int i = 0; i < mParameters.Count; i++) {
					if (mParameters[i].ImplementationTypeName != subset.mParameters[i].ImplementationTypeName)
						return (false);
				}

				return (true);
			} else {

				// Uhm... double-check

				// Parameter count
				if (mParameters.Count != subset.mParameters.Count)
					return (false);

				// Parameter type
				for (int i = 0; i < mParameters.Count; i++) {
					if (mParameters[i].ImplementationTypeName != subset.mParameters[i].ImplementationTypeName)
						return (false);
				}

				return (true);
			}
		}

		public bool HasSuperset
		{
			get { return (mHasSupersetImplementation); }
			set { mHasSupersetImplementation = value; }
		}

		public List<Function> SubsetFunctions = new List<Function>();

		/// <summary>
		/// Compose function implementation.
		/// </summary>
		/// <returns>
		/// It returns an array of strings specifying the function implementation definition, using
		/// parameters defined directly by function specification.
		/// </returns>
		public string[] GetImplementation()
		{
			return (GetImplementation(mParameters));
		}

		public void CheckForOverloadCollisions(Function overloadFunction)
		{
			for (int i = 0; i < mParameters.Count; i++) {
				if (mParameters[i].HasAlternatives && overloadFunction.mParameters[i].HasAlternatives) {
					foreach (Parameter alternative in mParameters[i].Alternatives) {
						foreach (Parameter overloadAlternative in overloadFunction.mParameters[i].Alternatives) {
							if (alternative.ImplementationTypeName == overloadAlternative.ImplementationTypeName) {
								// We have a collision
								if (ImportName != overloadFunction.ImportName) {
									// Different function imports: disable function renaming
									alternative.CauseOverrideCollision = overloadAlternative.CauseOverrideCollision = true;
								} else {
									;
								}
							}
						}
					}
				}
			}
		}

		public bool HasOverloadedImplementations
		{
			get
			{
				foreach (Parameter p in mParameters) {
					if (p.HasAlternatives == true) {
						return (true);
					}
				}

				return (false);
			}
		}

		/// <summary>
		/// Compose alternative function implementation.
		/// </summary>
		/// <returns>
		/// It returns an array of strings specifying the function implementation definition, using
		/// alternative parameters respect the original function specification.
		/// </returns>
		public string[] GetOverloadedImplementations()
		{
			List<string> oImplementation = new List<string>();
			string[] sImplementation;
			int[] pCombinationMap = new int[mParameters.Count];
			int pIndex = 0, pOverloaded = 0;

			// Determine number of overloaded parameters
			// @todo Works because only one parameter has an alternative!
			foreach (Parameter p in mParameters) {
				if (p.HasAlternatives == true) {
					pCombinationMap[pIndex] += p.Alternatives.Count;
					pOverloaded++;
				}

				pIndex++;
			}

			if (pOverloaded > 0) {
				// Select last parameter for overloading todo generate all combinations?

				pIndex = mParameters.Count - 1;
				while (pCombinationMap[pIndex] == 0) pIndex--;

				for (int overloadIndex = 0; overloadIndex < pCombinationMap[pIndex]; overloadIndex++) {
					List<Parameter> pOverloadedList = new List<Parameter>();
					bool collision = false;

					for (int i = 0; i < mParameters.Count; i++) {
						Parameter p = (i != pIndex) ? mParameters[i] : mParameters[i].Alternatives[overloadIndex];

						pOverloadedList.Add(p);
						collision = collision || p.CauseOverrideCollision;
					}

					// Obtain overloaded implementation
					sImplementation = GetImplementation(pOverloadedList);
					// Append overloaded implementation
					oImplementation.AddRange(sImplementation);
					oImplementation.Add("");
				}
			}

			if (oImplementation.Count > 0)
				return (oImplementation.ToArray());
			else
				return (null);
		}

		/// <summary>
		/// Compose function implementation.
		/// </summary>
		/// <param name="sig">
		/// A <see cref="System.String"/> specifying the function parameters.
		/// </param>
		/// <returns>
		/// It returns an array of strings specifying the function implementation definition.
		/// </returns>
		private string[] GetImplementation(List<Parameter> parameters)
		{
			List<string> sImplementation = new List<string>();
			string sTabs = "";
			bool safe, pinned, sFixed = false;

			// Check for safe implementation
			safe = IsSafeImplementation(parameters);
			// Check for pinnned implementation
			pinned = IsPinnedImplementation(parameters);

			// Documentation comments
			sImplementation.AddRange(GetImplementationDoc(parameters));
			// Open function scope
			sImplementation.Add(sTabs+"public static "+GetImplementationSignature(parameters)+" {"); sTabs += "	";
			if (HasReturnedValue == true)
				sImplementation.Add(sTabs+GetImplementationReturnType()+" retvalue;");

			// Open unsafe scope
			if (safe == false) {
				sImplementation.Add(sTabs+"unsafe {"); sTabs += "	";
			}
			// Open pinned statements scope
			if (pinned == true) {
				foreach (Parameter p in parameters)
					if (p.IsPinned == true) sImplementation.Add(sTabs+p.GetPinnedPointer());
				sImplementation.Add(sTabs+"try {"); sTabs += "	";
			}
			// Open fixed scope
			if (safe == false) {
				foreach (Parameter p in parameters) {
					if (p.IsSafe == false) {
						string pFixed = p.GetFixedPointer();

						if (pFixed != null) {
							sImplementation.Add(sTabs+pFixed);
							sFixed = true;
						}
					}
				}
				if (sFixed == true) {
					sImplementation.Add(sTabs+"{"); sTabs += "	";
				}
			}

			// Recall core function delegate
			sImplementation.Add(sTabs+"if      (Delegates."+DelegateName+" != null)");
			sImplementation.Add(sTabs+"	"+GetImplementationDelegateCall(this, parameters)+";");
			if (SubsetFunctions.Count > 0) {
				foreach (Function subset in SubsetFunctions) {
					sImplementation.Add(sTabs+"else if (Delegates."+subset.DelegateName+" != null)");
					sImplementation.Add(sTabs+"	"+GetImplementationDelegateCall(subset, parameters)+";");
				}
			}
			sImplementation.Add(sTabs+"else");
			sImplementation.Add(sTabs+"	throw new InvalidOperationException(\"binding point " + ImplementationName + " cannot be found\");");

			// Close fixed scope
			if (sFixed == true) {
				sTabs = sTabs.Substring(1); sImplementation.Add(sTabs+"}");
			}
			// Close pinned statements scope
			if (pinned == true) {
				sTabs = sTabs.Substring(1); sImplementation.Add(sTabs+"} finally {"); sTabs += "	";
				foreach (Parameter p in parameters) {
					if (p.IsPinned == true) {
						sImplementation.Add(sTabs+p.GetName(Parameter.PP_PREFIX)+".Free();");
					}
				}
				sTabs = sTabs.Substring(1); sImplementation.Add(sTabs+"}");
			}
			// Close unsafe scope
			if (safe == false) {
				sTabs = sTabs.Substring(1); sImplementation.Add(sTabs+"}");
			}

			// Include logging capability at the end for catching outputted values
			sImplementation.AddRange(GetImplementationLog(parameters, sTabs));

			// Returned value
			if (HasReturnedValue == true)
				sImplementation.Add(sTabs+"return (retvalue);");

			// Close function scope
			sTabs = sTabs.Substring(1); sImplementation.Add(sTabs+"}");

			return (sImplementation.ToArray());
		}

		private string[] GetImplementationLog(List<Parameter> parameters, string sTabs)
		{
			List<string> sImplementation = new List<string>();
			StringBuilder formatString = new StringBuilder();
			StringBuilder argsString = new StringBuilder();
			int paramIndex = 0;

			formatString.AppendFormat("\"{0}(", ImportName);
			
			foreach (Parameter p in parameters) {
				formatString.AppendFormat("{0}, ", "{"+paramIndex+"}");
				paramIndex++;

				if (p.Indirection != Parameter.IndirectionMode.ByPointer) {
					argsString.AppendFormat("{0}, ", p.Name);
				} else
					argsString.AppendFormat("\"{0}\", ", p.Name);
			}
			if (formatString.Length > 2)
				formatString.Remove(formatString.Length-2, 2);
			if (argsString.Length > 2)
				argsString.Remove(argsString.Length-2, 2);

			formatString.Append(")\"");

			if (HasReturnedValue == true) {
				formatString.Remove(formatString.Length - 1, 1);
				formatString.AppendFormat(" = {0}\"", "{" + paramIndex + "}");

				string retType = GetImplementationReturnType();
				
				if (retType.EndsWith("*"))
					argsString.AppendFormat(", (retvalue != null) ? (*retvalue).ToInt32() : 0");
				else
				    argsString.AppendFormat(", retvalue");
			}

			if (parameters.Count > 0) {
				sImplementation.Add(sTabs+"LogProc("+formatString+", "+argsString+");");
			} else
				sImplementation.Add(sTabs+"LogProc(\""+ImportName+"()\");");

			return (sImplementation.ToArray());
		}

		/// <summary>
		/// Check for safe function implementation.
		/// </summary>
		/// <param name="parameters">
		/// A <see cref="LinkedList<Parameter>"/> specifying the actually used function parameters.
		/// </param>
		/// <returns>
		/// It returns true whether the function implementation is safe, otherwise it returns
		/// false.
		/// </returns>
		private bool IsSafeImplementation(List<Parameter> parameters)
		{
			// Check for unsafe function, because parameter
			foreach (Parameter p in parameters) {
				if (p.IsSafe == false)
					return (false);
			}
			// Check for unsafe function, because array returned value
			if ((ReturnedValueType == "string") || (ReturnedValueType.EndsWith("[]") == true))
				return (false);

			return (true);
		}

		/// <summary>
		/// Check for pinned function implementation.
		/// </summary>
		/// <param name="parameters">
		/// A <see cref="LinkedList<Parameter>"/> specifying the actually used function parameters.
		/// </param>
		/// <returns></returns>
		private bool IsPinnedImplementation(List<Parameter> parameters)
		{
			// Check for pinned function parameter
			foreach (Parameter p in parameters) {
				if (p.IsPinned == true)
					return (true);
			}

			return (false);
		}

		/// <summary>
		/// Composed function implementation documentation.
		/// </summary>
		/// <param name="parameters">
		/// A <see cref="LinkedList<Parameter>"/> specifying the actually used function parameters.
		/// </param>
		/// <returns>
		/// It returns an array of strings specifying the function documentation.
		/// </returns>
		private string[] GetImplementationDoc(List<Parameter> parameters)
		{
			List<string> sDoc = new List<string>();
			ManualRoutine mRoutine = null;

			string docName;

			#region Match Function Manual by Function Import Name

			docName = ImportName;

			// Uses directly import name
			if (mRoutine == null)
				mRoutine = ManualDatabase.GetManual(docName);

			// Uses import name without extension and suffix
			if (mRoutine == null) {
				string ext, suffix;

				if ((ext = SpecDictionary.Instance.EndsWithExtension(docName)) != null)
					docName = docName.Substring(0, docName.Length - ext.Length);
				if ((suffix = SpecDictionary.Instance.EndsWithSuffix(docName)) != null)
					docName = docName.Substring(0, docName.Length - suffix.Length);

				mRoutine = ManualDatabase.GetManual(docName);
			}

			// Uses import name without extention, suffix and final number
			if (mRoutine == null) {
				if (docName.EndsWith("1") || docName.EndsWith("2") || docName.EndsWith("3") || docName.EndsWith("4"))
					docName = docName.Substring(0, docName.Length-1);
				if (docName.EndsWith("1I") || docName.EndsWith("2I") || docName.EndsWith("3I") || docName.EndsWith("4I"))
					docName = docName.Substring(0, docName.Length-2);
				if (docName.EndsWith("1D") || docName.EndsWith("2D") || docName.EndsWith("3D") || docName.EndsWith("4D"))
					docName = docName.Substring(0, docName.Length-2);

				mRoutine = ManualDatabase.GetManual(docName);
			}

			#endregion

			#region Match Function Manual by Function Implementation Name

			if (ImportNamePrefix == "gl") {
				docName = ImplementationName;

				// Uses directly implementation name
				if (mRoutine == null)
					mRoutine = ManualDatabase.GetManual(docName);

				// Uses directly implementation name (with gl prefix!)
				if (mRoutine == null)
					mRoutine = ManualDatabase.GetManual("gl" + docName);
			}

			#endregion

			// Summary
			if (mRoutine == null) {
				sDoc.Add("/// <summary>");
				sDoc.Add("/// Binding for " + ImportName + " function.");
				sDoc.Add("/// </summary>");
			
				// Parameters
				foreach (Parameter p in parameters) {
					string pDirComment = null, pArraySizeComment = null;

					// Determine input/output direction comment
					if (p.MDirection == Parameter.MarshalDirection.Out)
						pDirComment = "/// This parameter holds data returned from function.";
					// Determine array size comment
					if (p.Indirection == Parameter.IndirectionMode.ByArray) {
						switch (p.ArraySize) {
						case Parameter.ArraySizeMode.Fixed:
							pArraySizeComment = "/// This array parameter shall have a fixed length of "+p.GetFixedArraySize()+" element(s).";
							break;
						case Parameter.ArraySizeMode.SizeParam:
							pArraySizeComment = "/// This array parameter shall have a length dependent from parameter \"size\".";
							break;
						}
					}

					string pName = p.Name;
					string pType = p.ImportTypeName;
					Type pTypeInstance = TypeExtensions.GetTypeFromSimpleName(pType);

					// Parameter names corresponding to C# keywords are referenced without the leading '@'
					if (pName.StartsWith("@") == true) {
						pName = pName.Substring(1);
					}
					// Handle parameter array/pointer types
					if (pTypeInstance != null)
						pType = pTypeInstance.FullName.Trim();
					pType = "T:" + pType;

					sDoc.Add("/// <param name=\""+pName+"\">");
					sDoc.Add("/// A <see cref=\""+pType+"\"/>.");
					if (pDirComment != null) sDoc.Add(pDirComment);
					if (pArraySizeComment != null) sDoc.Add(pArraySizeComment);
					sDoc.Add("/// </param>");
				}
			} else {
				// Khronos documentation
				sDoc.AddRange(mRoutine.DocLines);
			}

			// Doxygen additional special commands
			if (Version != null)
				sDoc.Add("/// @note This routine is available from OpenGL " + Version);
			if (SubsetFunctions.Count > 1) {
				sDoc.Add("/// @note Depending on driver extension support, this routine will try to call the following (equivalent) routines, in the specified order:");
				sDoc.Add("/// - " + ImportName);
				foreach (Function subset in SubsetFunctions)
					sDoc.Add("/// - " + subset.ImportName);
			}
			if (IsDeprecated == true)
				sDoc.Add("/// @deprecated");

			return (sDoc.ToArray());
		}

		private List<string> GetWrappedString(string s)
		{
			const uint LINE_WIDTH = 100;

			List<string> wLines = new List<string>();
			string[] tokens = s.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
			string wLine = String.Empty;

			foreach (string token in tokens) {
				if (wLine.Length + token.Length + 1 > LINE_WIDTH) {
					wLines.Add(wLine);
					wLine = token;
					continue;
				} else
					wLine = wLine + " " + token;
			}
			wLines.Add(wLine);

			return (wLines);
		}

		/// <summary>
		/// Compose function implementation signature.
		/// </summary>
		/// <param name="parameters">
		/// A <see cref="LinkedList<Parameter>"/> specifying the actually used function parameters.
		/// </param>
		/// <returns>
		/// It returns a string specifying the function signature used by implementation.
		/// </returns>
		private string GetImplementationSignature(List<Parameter> parameters)
		{
			string sigFunctParams, sigRet = GetImplementationReturnType();
			int pNo = parameters.Count;
			bool nameCollision = false;

			#region Parameters

			// Function parameters
			sigFunctParams = "(";
			foreach (Parameter p in parameters) {
				string sigParam;

				nameCollision = nameCollision || p.CauseOverrideCollision;

				// Basic declaration
				sigParam = p.ImplementationTypeName + " " + p.Name;
				// Parameter attributes (marshal)
				if (p.MDirection == Parameter.MarshalDirection.Out)
					sigParam = "[Out] " + sigParam;
				// Parameter separator
				if (--pNo > 0) sigParam += ", ";

				// Append parameter declaration
				sigFunctParams += sigParam;
			}
			sigFunctParams += ")";

			#endregion

			return (sigRet + " " + ((nameCollision) ? ImportName.Substring(ImportNamePrefix.Length) : ImplementationName) + sigFunctParams);
		}

		private string GetImplementationDelegateCall(Function delegateAlias, List<Parameter> parameters)
		{
			List<Parameter> sDelegateParams = delegateAlias.GetParameters();
			string sDelegateCall = "Delegates."+delegateAlias.DelegateName+"(";

			#region Delegate Call Parameters

			for (int pCount = 0; pCount < parameters.Count; pCount ++) {
				if (parameters[pCount].DelegateTypeName == sDelegateParams[pCount].DelegateTypeName) {
					sDelegateCall += parameters[pCount].DelegateCallName;
				} else {
					if (sDelegateParams[pCount].DelegateTypeName == "IntPtr") {
						sDelegateCall += "new IntPtr((long)" + parameters[pCount].DelegateCallName + ")";
					} else {
						sDelegateCall += parameters[pCount].DelegateCallName;
					}
				}
				if (pCount < parameters.Count - 1) sDelegateCall += ", ";
			}
			sDelegateCall += ")";

			#endregion

			#region Delegate Return Statement
			
			string retValue = GetImplementationReturnType(), retTypeDelegate = GetDelegateReturnType();

			if (retValue != "void") {
				if ((retValue == "string") && (retTypeDelegate != "string"))
					sDelegateCall = "retvalue = (Marshal.PtrToStringAnsi("+sDelegateCall+"))";
				else
					sDelegateCall = "retvalue = ("+sDelegateCall+")";
			}

			#endregion

			return (sDelegateCall);
		}
		
		/// <summary>
		/// Determine the return value for function implementation.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/>
		/// </returns>
		private string GetImplementationReturnType()
		{
			string sigRet = SpecParser.GetCsSafeType(ReturnedValueType);
			
			if (sigRet == "byte[]")
				sigRet = "string";
			if (sigRet.EndsWith("[]"))
			    sigRet = SpecParser.GetCsUnsafeType(ReturnedValueType);
			
			return (sigRet);
		}

		/// <summary>
		/// Function name.
		/// </summary>
		private string mImplementationName = null;

		/// <summary>
		/// There's another function that is preferable.
		/// </summary>
		private bool mHasSupersetImplementation = false;

		#endregion

		#region Function Deprecation

		/// <summary>
		/// Deprecate this function.
		/// </summary>
		public void Deprecate()
		{
			mDeprecated = true;
		}

		/// <summary>
		/// Determine whether this function is deprecated.
		/// </summary>
		public bool IsDeprecated
		{
			get { return (mDeprecated); }
		}

		/// <summary>
		/// Function deprecation flag.
		/// </summary>
		private bool mDeprecated = false;

		#endregion

		#region Function Information

		/// <summary>
		/// Function category.
		/// </summary>
		public string Category = null;

		/// <summary>
		/// Function category.
		/// </summary>
		public string Alias = null;

		/// <summary>
		/// Function category.
		/// </summary>
		public string Version = null;

		/// <summary>
		/// Function excluded (only implementation)
		/// </summary>
		public bool ImplementationExcluded = false;

		#endregion
	}
}
